package com.facesdk;

import android.graphics.Bitmap;
import android.util.Base64;
import android.util.Log;

/**
 * Created by linc on 15-6-24.
 */
public class FaceRecognitionProcessor {
    private static final String TAG = "FaceRecogProcessor";

    /**
     * Detect eye.
     * @param data The gray image byte array.
     * @param width Width of image.
     * @param height Height of image.
     * @param faceLocation Face location.
     * @return EyeInfo.
     */
    public EyeInfo detectEye(byte[] data,int width,int height,FRect faceLocation){
        if(data == null || data.length <=0 || faceLocation == null) return null;
        return FDEyeProcessor.detectEye(data, width, height, faceLocation.getLeft(),
                faceLocation.getTop(), faceLocation.getWidth(),
                faceLocation.getHeight());
    }

    /**
     *  Detect face.
     * @param imageData The gray image byte array.
     * @param width Width of image.
     * @param height Height of image.
     * @return FaceInfo.
     */
    public FaceInfo detectFace(byte[] imageData, int width, int height){
        if(imageData==null||width<=0||height<=0) return null;
        Log.d(TAG, "detectFace: data length is " + imageData.length);
        FaceInfo faceInfo = null;
        if (imageData != null) {
            faceInfo = FDFaceProcessor.FDFace(imageData, width,
                    height,FDFaceProcessor.FSCALE,FDFaceProcessor.DEFAULT_MIN_WIDTH,
                    FDFaceProcessor.DEFAULT_MIN_HEIGHT,width,height);
        }

        return faceInfo;
    }

    public FaceInfo detectFace(byte[] imageData, int width, int height,
                               int minWidth,int minHeight){
        if(imageData==null||width<=0||height<=0) return null;
        Log.d(TAG, "detectFace: data length is " + imageData.length);
        FaceInfo faceInfo = null;
        if (imageData != null) {
            faceInfo = FDFaceProcessor.FDFace(imageData, width,
                    height,FDFaceProcessor.FSCALE,minWidth,minHeight,width,height);
        }

        return faceInfo;
    }
    /**
     * Detect face return FaceInfo
     * @param bitmap Original face bitmap.
     * @return FaceInfo which detect.
     */
    public FaceInfo detectFace(Bitmap bitmap){
        if (bitmap == null) return null;
        byte[] bytes = convertGrayByteArray(bitmap);
//        bytes = FDFaceProcessor.RGB2Gray(Utils.byteArray2intArray(bytes), bitmap.getWidth(),
//                bitmap.getHeight());

        FaceInfo faceInfo = null;
        if (bitmap != null)
            faceInfo = FDFaceProcessor.FDFace(bytes, bitmap.getWidth(),
                    bitmap.getHeight(),
                    FDFaceProcessor.FSCALE,
                    FDFaceProcessor.DEFAULT_MIN_WIDTH,
                    FDFaceProcessor.DEFAULT_MIN_HEIGHT,
                    bitmap.getWidth(),
                    bitmap.getHeight());

        return faceInfo;
    }

    /**
     * Build modeling.
     * @param bitmap face image original no convert gray.
     * @return feature code for Base64 String
     */
    public String getFeatureCode(Bitmap bitmap) {
        if(bitmap == null) return null;
        //bitmap
        byte[] data = convertGrayByteArray(bitmap);
        FaceInfo faceInfo = detectFace(data,bitmap.getWidth(),bitmap.getHeight());
        return getFeatureCode(faceInfo,data,bitmap.getWidth(),bitmap.getHeight());
    }

    /**
     * Get feature code of Base64 string.
     * When width and height of face rect >= 0.4 width and scanning rect, build the modeling.
     * @param bitmap the ID card bitmap
     * @return Feature code Base64 string.
     */
    public String getFeatureCodeRealTime(Bitmap bitmap) {
        if(bitmap == null) return null;
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Log.d(TAG,"scanning rect width: "+width+" height: "+height);
        String featureCode = null;
        byte[] data = convertGrayByteArray(bitmap);
        FaceInfo faceInfo = detectFace(data, width, height,(int)(0.4*width),(int)(0.4*height));

        if(faceInfo != null) {
            FRect rect = faceInfo.getFace_pos_arr().get(0);
            Log.d(TAG,"face rect top: "+rect.getTop()+" rect left"+rect.getLeft()+" rect height: "+
                    rect.getHeight()+" rect width: "+rect.getWidth());
            if(rect.getHeight()>=0.4*height && rect.getWidth() >= 0.4*width) {
                //build the modeling and save feature code.
                featureCode = getFeatureCode(faceInfo,data,width,height);
            }
        }
        return featureCode;
    }
    /**
     * Get feature code.
     * @param faceInfo FaceInfo.
     * @param data Bitmap byte array.
     * @param width Width of bitmap.
     * @param height Height of bitmap.
     * @return Feature code Base64 string.
     */
    public String getFeatureCode(FaceInfo faceInfo,byte[] data,int width,int height) {
        byte[] featureCode = getFeatureCodeByteArray(faceInfo,data,width,height);
        if(featureCode == null || featureCode.length == 0) return null;

        return (Base64.encodeToString(featureCode,Base64.DEFAULT));
    }

    public byte[] getFeatureCodeByteArray(FaceInfo faceInfo,byte[] data,int width,int height) {
        if(faceInfo == null || data == null || data.length <= 0) return null;

        EyeInfo eyeInfo = detectEye(data, width, height,
                faceInfo.getFace_pos_arr().get(0));
        if (eyeInfo == null) return null;

        byte[] featureCode = FaceFeatureProcessor.GetFeatureCodeV2(data, width,
                height, eyeInfo.getLeftx(), eyeInfo.getLefty(),
                eyeInfo.getRightx(), eyeInfo.getRighty());
        if(featureCode == null || featureCode.length == 0) return null;

        Log.d(TAG,"featureCode length: "+featureCode.length);
        return featureCode;
    }

    /**
     * Compare two feature code Base64 String.
     * @param base64String1 The first feature code Base64 string.
     * @param base64String2 The second feature code Base64 string.
     * @return The result of compare.
     */
    public double compareFeatureCode(String base64String1,String base64String2) {
        byte[] featureCode1 = Base64.decode(base64String1,Base64.DEFAULT);
        byte[] featureCode2 = Base64.decode(base64String2, Base64.DEFAULT);
        double result = FaceFeatureProcessor.CompareCodeV2(featureCode1,
                featureCode2, FRVectorDistanceType.FR_ANGLECOS);

        return result;
    }

    /**
     * Convert bitmap to Gray byte array
     * @param bitmap Original bitmap
     * @return Gray byte array.
     */
    public byte[] convertGrayByteArray(Bitmap bitmap){
        if(bitmap == null) return null;
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] i_arr = new int[width * height];
        bitmap.getPixels(i_arr, 0, width, 0, 0, width, height);
        return FDFaceProcessor.RGB2Gray(i_arr,width,height);
    }
}
